<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Simple Groups Example</title>
    <style>
        @import url(../style.css);

        .node {
            stroke: #fff;
            stroke-width: 1.5px;
        }

        .link {
            stroke: #999;
            stroke-opacity: .8;
        }

        .group {
            stroke: #fff;
            stroke-width: 1.5px;
            opacity: 0.2;
        }
    </style>
</head>
<body>
    <a href="../index.html">cola.js home</a>
    <h1>Simple Groups Example</h1>
    <script src="../extern/d3v4.js"></script>
    <script src="../cola.min.js"></script>
    <link rel="stylesheet" href="../extern/hljs/styles/github.css">
    <script src="../extern/hljs/highlight.pack.js"></script>
    <!--<script src="../src/rbtree.js"></script>
    <script src="../src/pqueue.js"></script>
    <script src="../src/vpsc.js"></script>
    <script src="../src/rectangle.js"></script>
    <script src="../src/descent.js"></script>
    <script src="../src/pqueue.js"></script>
    <script src="../src/shortestpaths.js"></script>
    <script src="../src/linklengths.js"></script>
    <script src="../src/handledisconnected.js"></script>
    <script src="../src/layout.js"></script>
    <script src="../src/rbtree.js"></script>
    <script src="../src/d3adaptor.js"></script>-->
    <script>
        hljs.initHighlightingOnLoad();
        var width = 960,
            height = 500;

        var color = d3.scaleOrdinal(d3.schemeCategory20);

        var cola = cola.d3adaptor(d3)
            .size([width, height]);

        var svg = d3.select("body").append("svg")
            .attr("width", width)
            .attr("height", height);

        d3.json("graphdata/miserables.json", function (error, graph) {
            var groupMap = {};
            graph.nodes.forEach(function (v, i) {
                var g = v.group;
                if (typeof groupMap[g] == 'undefined') {
                    groupMap[g] = [];
                }
                groupMap[g].push(i);

                v.width = v.height = 10;
            });

            var groups = [];
            for (var g in groupMap) {
                groups.push({ id: g, leaves: groupMap[g] });
            }
            cola
                .nodes(graph.nodes)
                .links(graph.links)
                .groups(groups)
                .jaccardLinkLengths(40, 0.7)
                .avoidOverlaps(true)
                .start(50, 0, 50);

            var group = svg.selectAll('.group')
                .data(groups)
                .enter().append('rect')
                .classed('group', true)
                .attr('rx',5)
                .attr('ry',5)
                .style("fill", function (d) { return color(d.id); })
                .call(cola.drag);

            var link = svg.selectAll(".link")
                .data(graph.links)
              .enter().append("line")
                .attr("class", "link")
                .style("stroke-width", function (d) { return Math.sqrt(d.value); });

            var node = svg.selectAll(".node")
                .data(graph.nodes)
              .enter().append("circle")
                .attr("class", "node")
                .attr("r", 5)
                .style("fill", function (d) { return color(d.group); })
                .call(cola.drag);

            node.append("title")
                .text(function (d) { return d.name; });

            cola.on('tick', function () {
                link.attr("x1", function (d) { return d.source.x; })
                    .attr("y1", function (d) { return d.source.y; })
                    .attr("x2", function (d) { return d.target.x; })
                    .attr("y2", function (d) { return d.target.y; });

                node.attr("cx", function (d) { return d.x; })
                    .attr("cy", function (d) { return d.y; });

                group
                    .attr('x', function (d) { return d.bounds.x })
                    .attr('y', function (d) { return d.bounds.y })
                    .attr('width', function (d) { return d.bounds.width() })
                    .attr('height', function(d) { return d.bounds.height() });
            });
        });

    </script>
    A very simple use of rectangular groups with no nesting.  Both nodes and groups are draggable.
    Telling cola about the groups is like so:
<pre><code>cola
    .nodes(graph.nodes)
    .links(graph.links)
    .groups(groups)
    .jaccardLinkLengths(40, 0.7)
    .avoidOverlaps(true)
    .start(20, 0, 10);
</code></pre>
    In the above, <code>groups</code> is an array where each group object contains a single property
    <code>leaves</code> which is an array of indices to the <code>graph.nodes</code> array.  We turn on <code>avoidOverlaps</code> to get cola to
    keep the nodes and groups separated.  The <code>start</code> method is called with three parameters 20, 0 and 10.  These are, respectively:
    <ul>
        <li>20 initial graph layout iterations without constraints to get the graph to untangle.</li>
        <li>0 iterations for structural constraints (none are specified so any iterations here would be the same as the previous step)</li>
        <li>10 iterations with non-overlap constraints</li>
    </ul>
    Setup for the group visuals is a typical D3 pattern:
<pre><code>var group = svg.selectAll('.group')
    .data(groups)
    .enter().append('rect')
    .classed('group', true)
    .attr({ rx: 5, ry: 5 })
    .style('fill', function (d) { return color(d.id) })
    .call(cola.drag);</code></pre>
    In the tick event handler we need to resize groups as well as moving them.  Cola puts this information into the <code>bounds</code> property on each group:

<pre><code>cola.on('tick', function () {
    ...
    group.attr({
        x: function (d) { return d.bounds.x },
        y: function (d) { return d.bounds.y },
        width: function (d) { return d.bounds.width() },
        height: function(d) { return d.bounds.height() }
    });
});</code></pre>
    <script>
    (function (i, s, o, g, r, a, m) {
        i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
            (i[r].q = i[r].q || []).push(arguments)
        }, i[r].l = 1 * new Date(); a = s.createElement(o),
        m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m)
    })(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');

    ga('create', 'UA-63535113-1', 'auto');
    ga('send', 'pageview');

    </script>
</body>
</html>
